﻿#include "OperLoadCase.h"

#include "GUIFrame/MainWindow.h"
#include "GUIWidget/ControlPanel.h"
#include "GUIWidget/TreeWidgetLoad.h"
#include "GUIWidget/TreeItemTypes.h"
#include "GUIFrame/CentralWidget.h"
#include "GUIDialog/GUIPostDialog/GUILoadCaseDialog.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsGeometryData.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractFESubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSensors.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractJunction.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsSolverLoadCase.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsPhysics.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsLoadManager.h"

#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsVirtualTopo.h"
#include "OperatorsInterface/GraphEventOperator.h"

#include <QTreeWidgetItem>
#include <QAction>
#include <QSet>

#define _DATAOBJIDCOLUMN_ 0
#define _DATAOBJID_ 1

namespace GUIOper
{
    bool OperLoadCase::execGUI()
    {
        //获取触发器
        if (!_emitter)return false;
        //获取动作名称
        QString name = _emitter->objectName();
        if (name == "actionCreateLoadCase")
            this->createLoadCaseOper();
        else if (name == "actionLoadCaseEdit")
            this->editOper();
        else if (name == "actionLoadCaseShow")
            this->showOper();
        else if (name == "actionLoadCaseHide")
            this->hideOper();
        else if (name == "actionLoadCaseShowOnly")
            this->showOnlyOper();
        return true;
    }

    bool OperLoadCase::execProfession()
    {
        return true;
    }

    void OperLoadCase::updateLoadCaseTreeSlot()
    {
        GUI::MainWindow* mw = GUI::MainWindow::GetMainWindowFromFramework();
        if (mw == nullptr ) return;
        GUI::CentralWidget* cw = mw->getCentralWidget();
        if (cw == nullptr) return;
        GUI::ControlPanel*  cp = cw->getControlPanel();
        if (cp == nullptr) return;
        GUI::TreeWidgetLoad* modelTree = dynamic_cast<GUI::TreeWidgetLoad*>(cp->getTreeWidget(GUI::TreeWidgetType::PageLoad));
        if (modelTree == nullptr) return;
        modelTree->updateLoadCaseTree();
    }

    void OperLoadCase::updateLoadCaseTreeState()
    {
        GUI::MainWindow* mw = GUI::MainWindow::GetMainWindowFromFramework();
        if (mw == nullptr) return;
        GUI::CentralWidget* cw = mw->getCentralWidget();
        if (cw == nullptr) return;
        GUI::ControlPanel*  cp = cw->getControlPanel();
        if (cp == nullptr) return;
        GUI::TreeWidgetLoad* modelTree = dynamic_cast<GUI::TreeWidgetLoad*>(cp->getTreeWidget(GUI::TreeWidgetType::PageLoad));
        if (modelTree == nullptr) return;
        modelTree->updateLoadCaseTreeItemState();
    }

    void OperLoadCase::createLoadCaseOper()
    {
        GUI::MainWindow * mainWindow = dynamic_cast<GUI::MainWindow *>(FITKAPP->getGlobalData()->getMainWindow());
        GUI::GUILoadCaseDialog* LoadCaseDialog = new GUI::GUILoadCaseDialog(this, mainWindow);
        connect(LoadCaseDialog, SIGNAL(accepted()), this, SLOT(updateLoadCaseTreeSlot()));
        LoadCaseDialog->show();
    }

    void OperLoadCase::editOper()
    {
        void* pItem = nullptr;
        this->argValue<void*>("SelectedItems", pItem);
        //获取编辑类型
        QList<QTreeWidgetItem*>* itemsList = (QList<QTreeWidgetItem*>*)(pItem);
        if (itemsList && !itemsList->isEmpty())
        {
            QTreeWidgetItem* item = itemsList->at(0);
            if (!item) return;
            if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCase)
            {
                int objID = item->data(_DATAOBJIDCOLUMN_, _DATAOBJID_).toInt();
                editLoadCaseOper(objID);
            }
            else if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCaseChild)
            {
                int objID = item->data(_DATAOBJIDCOLUMN_, _DATAOBJID_).toInt();
                Core::FITKActionOperator* oper = FITKOPERREPO->getOperatorT<Core::FITKActionOperator>("actionEditLoad");
                if (!oper) return;
                QAction* actTemp = new QAction;
                actTemp->setObjectName("actionEditLoad");
                oper->setArgs("DataID", objID);
                oper->setEmitter(actTemp);
                oper->actionTriggered();
                delete actTemp;
            }
        }
    }

    void OperLoadCase::editLoadCaseOper(int LoadCaseObjID)
    {
        //编辑分组数据操作API
        GUI::MainWindow * mainWindow = dynamic_cast<GUI::MainWindow *>(FITKAPP->getGlobalData()->getMainWindow());
        GUI::GUILoadCaseDialog* LoadCaseDialog = new GUI::GUILoadCaseDialog(LoadCaseObjID, this, mainWindow);
        connect(LoadCaseDialog, SIGNAL(accepted()), this, SLOT(updateLoadCaseTreeSlot()));
        LoadCaseDialog->show();
    }

    void OperLoadCase::showOper()
    {
        //显示
        void* pItem = nullptr;
        this->argValue<void*>("SelectedItems", pItem);
        this->clearArgs();
        //获取数据
        bool isRoot = false;
        QList<int> LoadCaseObjID;
        QList<int> objIDList;
        QList<QTreeWidgetItem*>* itemsList = (QList<QTreeWidgetItem*>*)(pItem);
        for (int i = 0; i < itemsList->size(); ++i)
        {
            QTreeWidgetItem* item = itemsList->at(0);
            if (!item) return;
            int objID = item->data(_DATAOBJIDCOLUMN_, _DATAOBJID_).toInt();
            if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCaseRoot)
            {
                isRoot = true;
                break;
            }
            else if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCase && !LoadCaseObjID.contains(objID))
                LoadCaseObjID.append(objID);
            else if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCaseChild && !objIDList.contains(objID))
                objIDList.append(objID);
        }
        //更新分组的状态和选取数据
        this->updateLoadCaseState(LoadCaseObjID, objIDList, isRoot, true);
        this->setObjShowOrHide(objIDList, 1);
        this->updateLoadCaseTreeState();
    }

    void OperLoadCase::hideOper()
    {
        //隐藏
        void* pItem = nullptr;
        this->argValue<void*>("SelectedItems", pItem);
        this->clearArgs();
        //获取数据
        bool isRoot = false;
        QList<int> LoadCaseObjID;
        QList<int> objIDList;
        QList<QTreeWidgetItem*>* itemsList = (QList<QTreeWidgetItem*>*)(pItem);
        for (int i = 0; i < itemsList->size(); ++i)
        {
            QTreeWidgetItem* item = itemsList->at(0);
            if (!item) return;
            int objID = item->data(_DATAOBJIDCOLUMN_, _DATAOBJID_).toInt();
            if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCaseRoot)
            {
                isRoot = true;
                break;
            }
            else if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCase && !LoadCaseObjID.contains(objID))
                LoadCaseObjID.append(objID);
            else if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCaseChild && !objIDList.contains(objID))
                objIDList.append(objID);
        }
        //更新分组的状态和选取数据
        this->updateLoadCaseState(LoadCaseObjID, objIDList, isRoot, false);
        this->setObjShowOrHide(objIDList, 2);
        this->updateLoadCaseTreeState();
    }

    void OperLoadCase::showOnlyOper()
    {
        //仅显示
        void* pItem = nullptr;
        this->argValue<void*>("SelectedItems", pItem);
        this->clearArgs();
        //获取数据
        bool isRoot = false;
        QList<int> LoadCaseObjID;
        QList<int> objIDList;
        QList<QTreeWidgetItem*>* itemsList = (QList<QTreeWidgetItem*>*)(pItem);
        for (int i = 0; i < itemsList->size(); ++i)
        {
            QTreeWidgetItem* item = itemsList->at(0);
            if (!item) return;
            int objID = item->data(_DATAOBJIDCOLUMN_, _DATAOBJID_).toInt();
            if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCaseRoot)
            {
                isRoot = true;
                break;
            }
            else if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCase && !LoadCaseObjID.contains(objID))
                LoadCaseObjID.append(objID);
            else if (item->type() == GUI::LoadCaseTreeItemsType::LTLoadCaseChild && !objIDList.contains(objID))
                objIDList.append(objID);
        }
        //更新分组的状态和选取数据
        this->updateLoadCaseState(LoadCaseObjID, objIDList, isRoot, true);
        this->setObjShowOrHide(objIDList, 3);
        this->updateLoadCaseTreeState();
    }

    void OperLoadCase::updateLoadCaseState(QList<int> loadCaseIDList, QList<int>& objIDList, bool isRoot, bool state)
    {
        Acoustics::FITKAcousticsPhysics* physicsData = FITKAPP->getGlobalData()->getPhysicsData<Acoustics::FITKAcousticsPhysics>();
        if (!physicsData) return;
        Acoustics::FITKSolverLoadCaseManager* loadCaseManager = physicsData->getSolverLoadCaseManager();
        if (!loadCaseManager) return;
        int count = loadCaseManager->getDataCount();
        if (isRoot)
        {
            //设置全部状态
            loadCaseManager->enable(state);
            objIDList.clear();
            for (int i = 0; i < count; ++i)
            {
                Acoustics::FITKAcousticsSolverLoadCase* LoadCase = loadCaseManager->getDataByIndex(i);
                if (!LoadCase) continue;
                LoadCase->enable(state);
                objIDList.append(LoadCase->getLoadIDs());
            }
            return;
        }
        //获取操作数据对象ID
        QSet<int> objIDListSet = objIDList.toSet();
        for (int i = 0; i < count; ++i)
        {
            Acoustics::FITKAcousticsSolverLoadCase* LoadCase = loadCaseManager->getDataByIndex(i);
            if (!LoadCase) continue;
            int LoadCaseID = LoadCase->getDataObjectID();
            QSet<int> objIDs = LoadCase->getLoadIDs().toSet();
            if (!loadCaseIDList.contains(LoadCaseID)) continue;
            LoadCase->enable(state);
            objIDListSet.unite(objIDs);
        }
        objIDList = objIDListSet.toList();
        //设置LoadCase的状态
    }

    void OperLoadCase::setObjShowOrHide(QList<int> objList, int type)
    {
        bool state = true;
        bool isShow = false;
        if (type == 2)
            state = false;
        else if (type == 3)
            isShow = true;
        //获取渲染器
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (!operGraph) return;
        //获取数据管理器
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        Acoustics::FITKAcousticsPhysics* physicsData = FITKAPP->getGlobalData()->getPhysicsData<Acoustics::FITKAcousticsPhysics>();
        if (!discModel || !discModel->getFEModel() || !discModel->getSEAModel() || !physicsData)return;
        Acoustics::FITKAcousticsSEASubSysManager* subsysSEAManager = discModel->getSEAModel()->getSEASubSysManager();
        Acoustics::FITKAcousticsFESubSysManager* subsysFEManager = discModel->getFEModel()->getFESubSysManager();
        Acoustics::FITKAcousticsSensorsManager* sensorManager = discModel->getFEModel()->getSensorManager();
        Acoustics::FITKJunctionManager* junctionManager = discModel->getJunctionManager();
        Acoustics::FITKAcousticsLoadManager* loadManager = physicsData->getFITKAcousticsLoadManager();
        if (!subsysSEAManager || !subsysFEManager || !sensorManager || !junctionManager || !loadManager)return;
        //几何
        QList<Interface::FITKAbsVirtualTopo*> virTopoList = getAllGeometryVirTopos();
        for (Interface::FITKAbsVirtualTopo* virTopo : virTopoList) {
            if (!virTopo) continue;
            if (objList.contains(virTopo->getDataObjectID()))
                virTopo->enable(state);
            else if (isShow)
                virTopo->enable(false);
        }
        //SEA子系统
        for (int i = 0; i < subsysSEAManager->getDataCount(); i++) {
            Acoustics::FITKAbstractSEASubSys* subSys = subsysSEAManager->getDataByIndex(i);
            if (!subSys)continue;
            if (objList.contains(subSys->getDataObjectID()))
                subSys->enable(state);
            else if (isShow)
                subSys->enable(false);
        }
        //FE子系统
        for (int i = 0; i < subsysFEManager->getDataCount(); i++) {
            Acoustics::FITKAbstractFESubSys* subSys = subsysFEManager->getDataByIndex(i);
            if (!subSys)continue;
            if (objList.contains(subSys->getDataObjectID()))
                subSys->enable(state);
            else if (isShow)
                subSys->enable(false);
        }
        //传感器
        for (int i = 0; i < sensorManager->getDataCount(); i++) {
            Acoustics::FITKAcousticsSensors* sensor = sensorManager->getDataByIndex(i);
            if (!sensor)continue;
            if (objList.contains(sensor->getDataObjectID()))
                sensor->enable(state);
            else if (isShow)
                sensor->enable(false);
        }
        //junction
        for (int i = 0; i < junctionManager->getDataCount(); i++) {
            Acoustics::FITKAbstractJunction* junction = junctionManager->getDataByIndex(i);
            if (!junction)continue;
            if (objList.contains(junction->getDataObjectID()))
                junction->enable(state);
            else if (isShow)
                junction->enable(false);
        }
        //载荷
        for (int i = 0; i < loadManager->getDataCount(); i++) {
            Acoustics::FITKAcousticsAbstractLoad* load = loadManager->getDataByIndex(i);
            if (!load)continue;
            if (objList.contains(load->getDataObjectID()))
                load->enable(state);
            else if (isShow)
                load->enable(false);
        }
        //更新显示或隐藏
        operGraph->updateAllVisibility();
    }

    QList<Interface::FITKAbsVirtualTopo*> OperLoadCase::getAllGeometryVirTopos()
    {
        QList<Interface::FITKAbsVirtualTopo*> virTopoList = {};
        Acoustics::FITKAcousticsGeometryData* geometryData = FITKAPP->getGlobalData()->getGeometryData<Acoustics::FITKAcousticsGeometryData>();
        if (geometryData == nullptr) {
            return virTopoList;
        }

        //获取所有的集合命令
        QList<Interface::FITKAbsGeoCommand*> allGeo = {};
        const int n = geometryData->getDataCount();
        for (int i = 0; i < n; ++i) {
            Interface::FITKAbsGeoCommand* geo = geometryData->getDataByIndex(i);
            if (geo == nullptr) {
                continue;
            }
            allGeo.append(geo);
        }

        //获取所有点、线、面的虚拓扑
        for (Interface::FITKAbsGeoCommand* geoCom : allGeo) {
            if (geoCom == nullptr) {
                continue;
            }
            Interface::FITKShapeVirtualTopoManager* virTopoPointManager = geoCom->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSPoint);
            if (virTopoPointManager != nullptr) {
                for (int i = 0; i < virTopoPointManager->getDataCount(); i++) {
                    virTopoList.append(virTopoPointManager->getDataByIndex(i));
                }
            }
            Interface::FITKShapeVirtualTopoManager* virTopoEdgeManager = geoCom->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSEdge);
            if (virTopoEdgeManager != nullptr) {
                for (int i = 0; i < virTopoEdgeManager->getDataCount(); i++) {
                    virTopoList.append(virTopoEdgeManager->getDataByIndex(i));
                }
            }
            Interface::FITKShapeVirtualTopoManager* virTopoFaceManager = geoCom->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSFace);
            if (virTopoFaceManager != nullptr) {
                for (int i = 0; i < virTopoFaceManager->getDataCount(); i++) {
                    virTopoList.append(virTopoFaceManager->getDataByIndex(i));
                }
            }
        }
        return virTopoList;
    }
}
